#include "stdafx.h"

#include "BollingerCalculator.h"

#include <cmath>

#include "Market.h"
#include "Utils/Logger.h"

BollingerCalculatorManager::BollingerCalculatorManager()
{
}

BollingerCalculater& BollingerCalculatorManager::Add(BollingerParameter const& parameter)
{
	m_cs.Lock();
	BollingerCalculaterMap::iterator iter = m_bollingerCalculaterMap.find(parameter);
	if (iter == m_bollingerCalculaterMap.end())
	{
		iter = m_bollingerCalculaterMap.insert(std::make_pair(parameter,BollingerCalculater(parameter))).first;
		m_bollingerCalculatersMap[parameter.GetFarther()].push_back(&iter->second);
		m_bollingerCalculatersMap[parameter.GetNearby()].push_back(&iter->second);
	}
	m_cs.Unlock();
	return iter->second;
}

void BollingerCalculatorManager::DoOnMarket(Market const& market)
{
	m_cs.Lock();
	BollingerCalculatersMap::iterator iter = m_bollingerCalculatersMap.find(market.GetContract());
	if (iter != m_bollingerCalculatersMap.end())
	{
		BollingerCalculaters& bollingerCalculaters = iter->second;

		for (size_t index = 0; index < bollingerCalculaters.size(); ++index)
		{
			BollingerCalculater& bollingerCalculater = *bollingerCalculaters[index];
			bollingerCalculater.Calculate(market.GetContract(),market.GetLastPrice());
		}
	}
	m_cs.Unlock();
}


Bollingers const& BollingerCalculatorManager::GetBollingers(BollingerParameter const& parameter) const
{
	BollingerCalculaterMap::const_iterator iter = m_bollingerCalculaterMap.find(parameter);
	if (iter == m_bollingerCalculaterMap.end())
	{
		static Bollingers s_emtpyBollingers(1);
		return s_emtpyBollingers;
	}
	return iter->second.GetBollingers();
}

void BollingerCalculater::Calculate(int contract, double lastPrice)
{
	if (UpdateLastPrice(contract, lastPrice))
	{
		Calculate();
	}
}

bool BollingerCalculater::UpdateLastPrice(int contract, double lastPrice)
{
	if (m_parameter.IsFarther(contract))
		m_fartherLastPrice = lastPrice;
	else if (m_parameter.IsNearby(contract))
		m_nearLastPrice = lastPrice;
	else
	{
#ifndef LOG4CPLUS_DISABLE_ERROR
		FT formatter("Spread::UpdateLastPrice Contract[%d,%d] got incorrect contract[%d]",
			m_parameter.GetFarther(),m_parameter.GetNearby(),contract);
		LightLogger::Error(formatter);
#endif
		return false;
	}
	return true;
}

void BollingerCalculater::Calculate()
{
	if (m_fartherLastPrice != 0.00 && m_nearLastPrice != 0.00)
	{
		int newItemIndex = m_count%m_parameter.GetSpreadCount();
		double oldValue = m_spreads[newItemIndex];;
		double newValue = m_fartherLastPrice - m_nearLastPrice;
		m_sum += newValue - oldValue;
		m_squareSum += pow(newValue,2) - pow(oldValue,2);

		m_spreads[newItemIndex] = newValue;
		m_count++;
	}

	if (m_count >= m_parameter.GetSpreadCount())
	{
		double m = m_parameter.GetSpreadCount();
		double mid = m_sum/m;
		double STD = sqrt(m_squareSum/m-mid*mid);
		double SPREAD = STD*m_parameter.GetQuotiety();
		Bollinger bollinger(mid+SPREAD,mid-SPREAD);

		m_bollingers.AddBollinger(bollinger);
	}
}

void Bollingers::AddBollinger(Bollinger const& bollinger)
{
	int newItemIndex = m_count%m_maxCount;
	Bollinger& rewriteBollinger = m_bollingers[newItemIndex];
	Bollinger oldBollinger = rewriteBollinger;
	rewriteBollinger = bollinger;
	m_count++;
//	CalcAverage(oldBollinger,bollinger);
}

void Bollingers::CalcAverage(Bollinger const& oldBollinger, Bollinger const& newBollinger)
{
	int oldCount = m_count - 1;
	double upperSum = m_average.GetUpper() * oldCount;
	double lowerSum = m_average.GetLower() * oldCount;
	upperSum += newBollinger.GetUpper()-oldBollinger.GetUpper();
	lowerSum += newBollinger.GetLower()-oldBollinger.GetLower();

	m_average = Bollinger(upperSum/m_count,lowerSum/m_count);
}

